import json
import asyncio
import os
import aio_pika
from datetime import datetime
from aiogram import Bot, Dispatcher, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.storage.memory import MemoryStorage
from apscheduler.schedulers.asyncio import AsyncIOScheduler

from sqlalchemy import create_engine, Column, Integer, String, Date, Boolean
from sqlalchemy.orm import sessionmaker, declarative_base
from aiogram.filters import CommandStart, CommandObject

import config

# Инициализация бота
TOKEN = config.TOKEN
bot = Bot(token=TOKEN)
dp = Dispatcher(storage=MemoryStorage())

# Инициализация базы данных
Base = declarative_base()
engine = create_engine('sqlite:///users.db')
Session = sessionmaker(bind=engine)



# Модель данных
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer)
    value = Column(String)

class Message(Base):
    __tablename__ = 'messages'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer)
    message = Column(String)
    date = Column(Date)
    tourID = Column(Integer)
    isSent = Column(Boolean, default=False)


Base.metadata.create_all(engine)

# Обработчик команды start?=id_пользователя
@dp.message(CommandStart(deep_link=True))
async def start_command(message: types.Message, command: CommandObject):
    value = command.args
    if not value.isdigit():
        await message.reply("Ошибка привязки")
        return
    session = Session()
    user = session.query(User).filter_by(user_id=message.from_user.id).first()
    if user is None:
        session.add(User(user_id=message.from_user.id, value=value))
    else:
        session.query(User).filter_by(user_id=message.from_user.id).update({User.value: value})
    session.commit()
    await message.reply("Вы успешно привязали телеграм к аккаунту.")
    session.close()

async def send_message_to_user(user_id, message_text):
    session = Session()
    user = session.query(User).filter_by(value=user_id).first()
    if user is not None:
        chat_id = user.user_id
        await bot.send_message(chat_id=chat_id, text=message_text)
    session.close()

async def addMessageToDB(user_id, message_text, date, tourID):
    session = Session()
    session.add(Message(user_id=user_id, message=message_text, date=date, tourID=tourID))
    session.commit()
    session.close()

async def removeMessageFromDB(user_id, tourID):
    session = Session()
    session.query(Message).filter_by(user_id=user_id, tourID=tourID).delete()
    session.commit()
    session.close()

async def process_message(message: aio_pika.IncomingMessage):
    async with message.process():
        print('recieved message')
        data = json.loads(message.body)
        if 'message' in data:
            message_text = data['message']

        if data['type'] == 'add':
            user_id = data['user_id']
            date = datetime.strptime(data['date'], '%m.%d.%Y')
            tourID = data['tourID']
            await addMessageToDB(user_id, message_text, date, tourID)
        elif data['type'] == 'delete':
            user_id = data['user_id']
            tourID = data['tourID']
            await removeMessageFromDB(user_id, tourID)


async def rabbitmq_consumer():
    connection = await aio_pika.connect(config.RABBIT)
    channel = await connection.channel()
    queue = await channel.declare_queue('messages')
    await queue.consume(process_message)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    await asyncio.Future()  # run forever


async def check_messages():
    session = Session()
    messages = session.query(Message).filter_by(isSent=False, date=datetime.now().date()).all()
    session.close()
    for message in messages:
        await send_message_to_user(message.user_id, message.message)
        session = Session()
        session.query(Message).filter_by(id=message.id).update({Message.isSent: True})
        session.commit()
        session.close()



async def main():
    scheduler = AsyncIOScheduler()
    scheduler.add_job(check_messages, trigger='interval', minutes=1)
    scheduler.start()
    await asyncio.gather(
        dp.start_polling(bot),
        rabbitmq_consumer(),
    )

if __name__ == '__main__':
    asyncio.run(main())